#include "ViewportDirectDraw.h"

#include "RenderMethodDirectDraw.h"

namespace YoghurtGum
{

	ViewportDirectDraw::ViewportDirectDraw(uint32 a_Width, uint32 a_Height, uint32 a_Type /*= YG_VIEWPORT_TYPE_NOTHING*/) : Viewport(a_Width, a_Height, a_Type)
	{
		ZeroMemory(&m_Settings, sizeof(m_Settings));
		m_Settings.dwSize	= sizeof(m_Settings);

		m_Settings.dwFlags	= DDSD_WIDTH | DDSD_HEIGHT;
		m_Settings.dwWidth	= a_Width;
		m_Settings.dwHeight	= a_Height;

		m_X = 0.f;
		m_Y = 0.f;
		m_Width = a_Width;
		m_Height = a_Height;

		LPDIRECTDRAW ddroot = RenderMethodDirectDraw::GetSingleton()->GetObject();
		if (ErrorDirectDraw::Failed(ddroot->CreateSurface(
					&m_Settings, 
					&m_Surface, 
					NULL
				)
			)
		)
		{
			ERROR_EXPLAIN("Failed to create surface.");
		}

		SetType(a_Type);

		if (m_Properties & YG_VIEWPORT_DEFAULT || m_Properties & YG_VIEWPORT_CENTER || m_Properties & YG_VIEWPORT_SCALEX)
		{
			// create the m_clipper
			if (ErrorDirectDraw::Failed(ddroot->CreateClipper(
						0,
						&m_Clipper, 
						NULL
					)
				)
			)
			{
				ERROR_EXPLAIN("Failed to create clipping device.");
			}

			if (ErrorDirectDraw::Failed(m_Clipper->SetHWnd(
						0, 
						RenderMethodDirectDraw::GetSingleton()->GetWindowHandle()
					)
				)
			)
			{
				ERROR_EXPLAIN("Failed to attach clipping device to window.");
			}


			if (ErrorDirectDraw::Failed(m_Surface->SetClipper(
						m_Clipper
					)
				)
			)
			{
				ERROR_EXPLAIN("Failed to attach clipping device to backbuffer.");
			}
		}

		uint32 x = 0;
		uint32 y = 0;
		uint32 width = a_Width;
		uint32 height = a_Height;
		
		if (m_Properties & YG_VIEWPORT_CENTER)
		{
			x = (GetSystemMetrics(SM_CXSCREEN) / 2) - (a_Width / 2);
			y = (GetSystemMetrics(SM_CYSCREEN) / 2) - (a_Height / 2);
		}
		else if (m_Properties & YG_VIEWPORT_SCALEX)
		{
			real32 w = (real32)a_Width;
			real32 h = (real32)a_Height;
			real32 scale = (real32)(GetSystemMetrics(SM_CXSCREEN)) / w;

			width = (uint32)(w * scale);
			height = (uint32)(h * scale);
			x = 0;
			y = (GetSystemMetrics(SM_CYSCREEN) / 2) - (height / 2);
		}

		Log::GetSingleton().Print("Viewport: (%i, %i) (%i, %i)", x, y, width, height);

		SetDimensions(width, height);
		SetTargetPosition(x, y);

		Log::GetSingleton().Print("Target rectangle: (%i, %i)(%i, %i)", 
			m_Target.left, m_Target.top, 
			m_Target.right, m_Target.bottom
		);
	}

	ViewportDirectDraw::~ViewportDirectDraw()
	{

	}

	void ViewportDirectDraw::Resize(uint32 a_Width, uint32 a_Height)
	{
		YG_STUB;
	}

	void ViewportDirectDraw::SetType(uint32 a_Type)
	{
		m_Properties |= a_Type;
	}

	void ViewportDirectDraw::SetX(real32 a_X)
	{
		m_X = a_X;
	}

	void ViewportDirectDraw::SetY(real32 a_Y)
	{
		m_Y = a_Y;
	}

	void ViewportDirectDraw::SetPosition(real32 a_X, real32 a_Y)
	{
		m_X = a_X;
		m_Y = a_Y;
	}

	void ViewportDirectDraw::Move(real32 a_SpeedX, real32 a_SpeedY)
	{
		m_X += a_SpeedX;
		m_Y += a_SpeedY;
	}

	void ViewportDirectDraw::SetTargetPosition(uint32 a_X, uint32 a_Y)
	{
		CopyRect(&m_Target, &m_Dimensions);	
		m_OffsetX = a_X;
		m_OffsetY = a_Y;
		OffsetRect(&m_Target, m_OffsetX, m_OffsetY);
	}

	void ViewportDirectDraw::SetDimensions(uint32 a_Width, uint32 a_Height)
	{
		SetRect(
			&m_Dimensions, 
			0, 0, 
			a_Width, a_Height
		);
		m_CenterX = a_Width / 2;
		m_CenterY = a_Height / 2;
		SetTargetPosition(m_OffsetX, m_OffsetY);

		//m_Width = a_Width;
		//m_Height = a_Height;
	}

	bool ViewportDirectDraw::Enable()
	{
		return true;
	}

	bool ViewportDirectDraw::Disable()
	{
		if (m_Properties & YG_VIEWPORT_DEFAULT)
		{
			if (ErrorDirectDraw::Failed(m_TargetSurface->Blt(
							&m_Dimensions,
							m_Surface,
							NULL,
							NULL,
							NULL
						)
					)
				)
			{
				ERROR_EXPLAIN("Failed to copy backbuffer to frontbuffer.");
				return false;
			}
		}
		else if (m_Properties & YG_VIEWPORT_CENTER || m_Properties & YG_VIEWPORT_SCALEX)
		{
			if (ErrorDirectDraw::Failed(m_TargetSurface->Blt(
							&m_Target,
							m_Surface,
							NULL,
							NULL,
							NULL
						)
					)
				)
			{
				ERROR_EXPLAIN("Failed to copy backbuffer to frontbuffer.");
				return false;
			}
		}

		return true;
	}

	Vec2 ViewportDirectDraw::GetScreenPosition(Vec2 a_WorldPos)
	{
		//return Vec2(0, 0);
		Vec2 result;
		result.x = a_WorldPos.x - m_OffsetX;
		result.y = a_WorldPos.y - m_OffsetY;
		while (result.x > m_Width)
		{
			result.x -= m_Width;
		}
		while (result.y > m_Height)
		{
			result.y -= m_Height;
		}
		return result;
	}

	Vec2 ViewportDirectDraw::GetCenterPosition(Vec2 a_WorldPos)
	{
		//return Vec2(0, 0);
		Vec2 result = a_WorldPos;
		if (a_WorldPos.x > (float)m_CenterX - m_Bounds.x) 
		{ 
			result.x = (float)m_CenterX - m_Bounds.x; 
			m_OffsetX = a_WorldPos.x - result.x;
		}
		if (a_WorldPos.x > m_WorldX - m_CenterX - m_Bounds.x) 
		{ 
			result.x = a_WorldPos.x - (m_WorldX - m_CenterX - m_Bounds.x) + (m_CenterX - m_Bounds.x); 
			m_OffsetX = m_WorldX - m_Width;
		}
		if (a_WorldPos.y > (float)m_CenterY - m_Bounds.y) 
		{ 
			result.y = (float)m_CenterY - m_Bounds.y; 
			m_OffsetY = a_WorldPos.y - result.y;
		}
		if (a_WorldPos.y > m_WorldY - m_CenterY - m_Bounds.y) 
		{ 
			result.y = a_WorldPos.y - (m_WorldY - m_CenterY - m_Bounds.y) + (m_CenterY - m_Bounds.y); 
			m_OffsetY = m_WorldY - m_Height;
		}

		return result;
	}

	void ViewportDirectDraw::SetWorldDimensions(uint32 a_Width, uint32 a_Height)
	{
		m_WorldX = a_Width;
		m_WorldY = a_Height;
	}

	void ViewportDirectDraw::SetBounds(Vec2 a_Dim)
	{
		m_Bounds = a_Dim;
	}

}; // namespace YoghurtGum